package com.brillilab.service.logic.space;

import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.exceptions.BrillilabException;
import com.brillilab.domain.enums.lab.LabMemberPowerEnum;
import com.brillilab.domain.enums.space.BoxTypeEnum;
import com.brillilab.domain.enums.space.SpaceTypeEnum;
import com.brillilab.domain.po.kit.ReagentType;
import com.brillilab.domain.po.lab.Lab;
import com.brillilab.domain.po.space.*;
import com.brillilab.domain.po.system.Dict;
import com.brillilab.domain.vo.common.KeyValue;
import com.brillilab.domain.vo.kit.ReagentTypeVo;
import com.brillilab.domain.vo.lab.LabMemberVo;
import com.brillilab.domain.vo.print.BoxPrintVo;
import com.brillilab.domain.vo.print.PanelPrintVo;
import com.brillilab.domain.vo.space.BoxAdd;
import com.brillilab.domain.vo.space.BoxModify;
import com.brillilab.domain.vo.space.BoxVo;
import com.brillilab.domain.vo.space.BoxWithGridList;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.inventory.IReagentInventoryService;
import com.brillilab.service.core.kit.IReagentTypeService;
import com.brillilab.service.core.lab.ILabMemberService;
import com.brillilab.service.core.lab.ILabService;
import com.brillilab.service.core.space.IBoxService;
import com.brillilab.service.core.space.IPanelService;
import com.brillilab.service.core.system.IDictService;
import com.google.common.base.Splitter;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author wuzhiyu
 * @Title: BoxLogic
 * @ProjectName brill_lab
 * @Description: TODO
 * @date 2018/11/1515:50
 */
@Service
@Transactional
public class BoxLogic {
    @Resource
    private IBoxService boxService;
    @Resource
    private IReagentInventoryService reagentInventoryService;
    @Resource
    private IDictService dictService;
    @Resource
    private IPanelService panelService;

    @Resource
    private ILabMemberService labMemberService;
    @Resource
    private IReagentTypeService reagentTypeService;
    @Resource
    private ILabService labService;

    public boolean delete(Long id) {
        if (reagentInventoryService.InventoryCountInSpace(id, SpaceTypeEnum.BOX) > 0) {
            throw new BrillilabException(ResultEnum.DATA_EXIST_CANT_DELETE);
        }
        boxService.delete(id);
        panelService.deletePanelGridUsedByBoxId(id, BoxTypeEnum.REAGENT_BOX);
        return true;
    }

    public BoxVo add(BoxAdd boxAdd, Panel panel, UserInfoVo user) {
        Map<Integer, String> zoneMap = dictService.getZoneMap();
        List<Dict> colorList = dictService.getBoxColor();
        Optional<Dict> color = colorList.stream().filter(o -> o.getCode().equals(boxAdd.getBoxColor())).findFirst();
        Assert.notNull(color.get(), "color not exist");
        List<PanelGridUsed> usedList = panelService.getPanelGridUsedList(panel.getId());
        Box box = new Box();
        box.setLabMemberId(boxAdd.getLabMemberId());
        box.setIsDelete(0);
        box.setBoxColor(color.get().getCode());
        box.setColumns(boxAdd.getColumns());
        box.setDeviceId(panel.getDeviceId());
        box.setDeviceIndex(panel.getDeviceIndex());
        box.setHeight(boxAdd.getHeight());
        box.setLabId(panel.getLabId());
        box.setPanelId(panel.getId());
        box.setPanelName(panel.getName());
        box.setRoomName(panel.getRoomName());
        box.setRoomId(panel.getRoomId());
        box.setRows(boxAdd.getRows());
        box.setSpec(boxAdd.getSpec());
        box.setUserReagentType(boxAdd.getReagentTypes());
        box.setWidth(boxAdd.getWidth());
        box.setHeight(boxAdd.getHeight());
        box.setX(boxAdd.getX());
        box.setY(boxAdd.getY());
        box.setZone(panel.getZone());
        box.setRemark(boxAdd.getRemark());
        boxService.add(box);
        List<PanelGridUsed> panelGridUsedList = new ArrayList<>();
        for (int w = 0; w < boxAdd.getWidth(); w++) {
            for (int h = 0; h < boxAdd.getHeight(); h++) {
                PanelGridUsed used = new PanelGridUsed();
                used.setBoxId(box.getId());
                used.setPanelId(panel.getId());
                used.setRowNo(boxAdd.getY() + h);
                used.setColumnNo(boxAdd.getX() + w);
                if (CollectionUtils.isEmpty(usedList)) {
                    panelGridUsedList.add(used);
                } else {
                    Optional<PanelGridUsed> opt = usedList.stream().filter(u -> u.getRowNo().equals(used.getRowNo()) && u.getColumnNo().equals(used.getColumnNo())).findFirst();
                    if (opt.isPresent()) {
                        throw new BrillilabException(ResultEnum.DATA_ALREADY_EXIST);
                    } else {
                        panelGridUsedList.add(used);
                    }
                }
            }
        }
        panelService.addPanelGridUsedList(panelGridUsedList);
        BoxVo vo = new BoxVo();
        BeanUtils.copyProperties(box, vo);
        vo.setPanelGridUsedList(panelGridUsedList);
        vo.setZoneName(zoneMap.get(box.getZone()));
        List<ReagentTypeVo> reagentTypeList = reagentTypeService.selectAllSuReagentType(panel.getLabId(), null, null,null);
        List<Dict> specList = dictService.getTubeSize();
        List<LabMemberVo> memList = labMemberService.selectList(panel.getLabId(), null);
        if (!StringUtils.isEmpty(box.getUserReagentType())) {
            String[] idArr = StringUtils.delimitedListToStringArray(box.getUserReagentType(), ",");
            if (idArr.length > 0) {
                List<String> idList = CollectionUtils.arrayToList(idArr);
                List<ReagentTypeVo> list = reagentTypeList.stream().filter(t -> idList.contains(t.getReagentTypeId().toString())).collect(Collectors.toList());
                String tags = StringUtils.collectionToDelimitedString(list.stream().map(ReagentTypeVo::getName).collect(Collectors.toList()), ",");
                vo.setTags(tags);
            }
        }
        vo.setTubeSize(specList.stream().filter(s -> s.getCode().equals(box.getSpec())).findFirst().get().getName());
        vo.setLabMemberName(box.getLabMemberId() == null ? "公用" : memList.stream().filter(m -> m.getLabMemberId().equals(box.getLabMemberId())).findFirst().get().getUserName());
        return vo;
    }

    public List<BoxVo> getBoxlist(Panel panel, UserInfoVo user) {
        labMemberService.selectList(panel.getLabId(), null);
        List<BoxVo> boxList = boxService.list(panel.getId());
        List<ReagentTypeVo> reagentTypeList = reagentTypeService.selectAllSuReagentType(panel.getLabId(), null, null,null);
        List<Dict> specList = dictService.getTubeSize();
        Map<Integer,String> zoneMap = dictService.getZoneMap();
        if (!CollectionUtils.isEmpty(boxList)) {
            List<LabMemberVo> memList = labMemberService.selectList(panel.getLabId(), null);
            boxList.forEach(b -> {
                if (!StringUtils.isEmpty(b.getUserReagentType())) {
                    String[] idArr = StringUtils.delimitedListToStringArray(b.getUserReagentType(), ",");
                    if (idArr.length > 0) {
                        List<String> idList = CollectionUtils.arrayToList(idArr);
                        List<String>   notEmptyidList=idList.stream().filter(s->!StringUtils.isEmpty(s)).collect(Collectors.toList());
                        List<ReagentTypeVo> list = reagentTypeList.stream().filter(t -> notEmptyidList.contains(t.getReagentTypeId().toString())).collect(Collectors.toList());
                        String tags = StringUtils.collectionToDelimitedString(list.stream().map(ReagentTypeVo::getName).collect(Collectors.toList()), ",");
                        b.setTags(tags);
                    }
                }
                b.setZoneName(zoneMap.get(b.getZone()));
                b.setTubeSize(specList.stream().filter(s -> s.getCode().equals(b.getSpec())).findFirst().get().getName());
                b.setLabMemberName(b.getLabMemberId() == null ? "公用" : memList.stream().filter(m -> m.getLabMemberId().equals(b.getLabMemberId())).findFirst().get().getUserName());
                b.setCanSee(b.getLabMemberId() == null ? true : (user.hasPower(LabMemberPowerEnum.Power.REAGENT) || b.getLabMemberId().equals(user.getLabMemberId())));
            });
        }
        return boxList;
    }

    public List<KeyValue<String, List<KeyValue<String, List<BoxPrintVo>>>>> getPrintList(Long labId) {
        List<Box> boxList = boxService.getLabBoxList(labId);
        List<KeyValue<String, List<KeyValue<String, List<BoxPrintVo>>>>> list = new ArrayList<>();
        List<Room> roomList = boxList.stream().map(d -> {
            Room room = new Room();
            room.setId(d.getRoomId());
            room.setName(d.getRoomName());
            return room;
        }).distinct().collect(Collectors.toList());
        Map<Integer, String> zoneMap = dictService.getZoneMap();
        Lab lab = labService.selectById(labId);
        roomList.forEach(r -> {
            KeyValue<String, List<KeyValue<String, List<BoxPrintVo>>>> kvr = new KeyValue<>();
            list.add(kvr);
            kvr.setKey(r.getName());
            List<KeyValue<String, List<BoxPrintVo>>> kvd = new ArrayList<>();
            kvr.setValue(kvd);
            List<Device> deviceList = boxList.stream().filter(p -> p.getRoomId().equals(r.getId())).map(p -> {
                Device d = new Device();
                d.setId(p.getDeviceId());
                d.setDeviceIndex(p.getDeviceIndex());
                d.setZone(p.getZone());
                return d;
            }).distinct().collect(Collectors.toList());
            deviceList.forEach(d -> {
                KeyValue<String, List<BoxPrintVo>> kvp = new KeyValue<>();
                kvd.add(kvp);
                kvp.setKey(d.getDeviceIndex() + "[" + zoneMap.get(d.getZone()) + "]");
                List<BoxPrintVo> printVoList = boxList.stream().filter(p -> p.getDeviceId().equals(d.getId())).map(p -> {
                    BoxPrintVo vo = new BoxPrintVo();
                    vo.setDeviceName(d.getDeviceIndex() + "");
                    vo.setDeviceIndex(d.getDeviceIndex());
                    vo.setPanelName(p.getPanelName());
                    vo.setBoxId(p.getId());
                    vo.setRoomName(r.getName());
                    vo.setZoneName(zoneMap.get(p.getZone()));
                    vo.setBoxColor(p.getBoxColor());
                    vo.setQrCode("labinone://inventoryQuery?boxId=" + p.getId());
                    vo.setLabName(lab.getName());
                    return vo;
                }).collect(Collectors.toList());
                kvp.setValue(printVoList);
            });
        });
        return list;
    }

    public BoxWithGridList getBoxWithGridList(Box box, UserInfoVo user) {
        List<Dict> specList = dictService.getTubeSize();
        BoxWithGridList bg = new BoxWithGridList();
        if (box.getLabMemberId() != null) {

            LabMemberVo memberVo = labMemberService.selectMemberVo(box.getLabMemberId());
            if (memberVo != null) {
                bg.setLabMemberName(memberVo.getUserName());
            }
        }
        if (org.apache.commons.lang.StringUtils.isEmpty(bg.getLabMemberName())) {
            bg.setLabMemberName("公用");
        }
        BoxVo bv=new BoxVo();
        BeanUtils.copyProperties(box,bv);
        bv.setTubeSize(specList.stream().filter(s -> s.getCode().equals(bv.getSpec())).findFirst().get().getName());
        bg.setBox(bv);
        bg.setGridList(boxService.getGridList(box.getId()));
        if (!StringUtils.isEmpty(box.getUserReagentType())) {
            List<String> arr = Splitter.on(",").omitEmptyStrings().splitToList(box.getUserReagentType());
            if (arr != null && arr.size() > 0) {
                List<ReagentTypeVo> typeVoList = reagentTypeService.getTypeList(box.getLabId(), null);
                StringBuffer sb = new StringBuffer();
                for (int x = 0; x < arr.size(); x++) {
                    Long i = new Long(arr.get(x));
                    Optional<ReagentTypeVo> opt = typeVoList.stream().filter(o -> o.getReagentTypeId().equals(i)).findFirst();
                    if (opt.isPresent()) {
                        if (x == arr.size() - 1) {
                            sb.append(opt.get().getName());
                        } else {
                            sb.append(opt.get().getName() + ",");
                        }
                    }
                }
                bg.setTags(sb.toString());
            }
        }
        return bg;
    }

    public boolean updateBox(BoxModify modify) {
        Box update = new Box();
        update.setId(modify.getId());
        update.setLabMemberId(modify.getLabMemberId());
        update.setUserReagentType(modify.getReagentTypes());
        update.setRemark(modify.getRemark());
        boxService.updateInfo(modify.getId(),modify.getLabMemberId(),modify.getRemark(),modify.getReagentTypes());
        if (update.getLabMemberId() != null) {
            boxService.updateGridAndInventoryOwner(modify.getId(), modify.getLabMemberId());
        }else{
            if(modify.getIsChangeAll()){
                boxService.updateGridAndInventoryOwner(modify.getId(), modify.getLabMemberId());
            }
        }
        return true;
    }

    public BoxPrintVo getPrint(UserInfoVo user, Long boxId) {
        Box box = boxService.get(boxId);
        Assert.notNull(box, "数据不存在");
        Assert.isTrue(box.getLabId().equals(user.getLabId()), "数据不存在");
        Map<Integer, String> zoneMap = dictService.getZoneMap();
        BoxPrintVo vo = new BoxPrintVo();
        vo.setDeviceName(box.getDeviceIndex() + "");
        vo.setDeviceIndex(box.getDeviceIndex());
        vo.setPanelName(box.getPanelName());
        vo.setBoxId(box.getId());
        vo.setRoomName(box.getRoomName());
        vo.setZoneName(zoneMap.get(box.getZone()));
        vo.setBoxColor(box.getBoxColor());
        vo.setQrCode("labinone://inventoryQuery?boxId=" + box.getId());
        Lab lab = labService.selectById(user.getLabId());
        vo.setLabName(lab.getName());
        return vo;
    }
}
